import cv2, imutils
import time
import pyzbar.pyzbar as pyzbar
import numpy as np

# 裁剪
# 宽度是x 顶点向右方向  高度是y ,顶点向下方向
crop_x_min = 0   
crop_x_max = 1000
crop_y_min = 590   
crop_y_max = 1890

kernel_2 = np.ones((2, 2), np.uint8)  # 2x2的卷积核
kernel_3 = np.ones((3, 3), np.uint8)  # 3x3的卷积核
kernel_4 = np.ones((4, 4), np.uint8)  # 4x4的卷积核

Lower_black = np.array([70, 100, 100])
Upper_black = np.array([87, 150, 120])
draw_black = (0,0,0)
black = [Lower_black, Upper_black, 'black',draw_black]

class frameClass:

    #### 形状识别
    def contour_recong(self,frame):
        max_area = 30000
        min_area = 3000
        ###----轮廓检测的第一种方法 切换为HSV通道，进行初步的颜色筛选后，进行轮廓的提取----####
        HSV = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
        color = black
        mask_= cv2.inRange(HSV, color[0], color[1])
        ## 腐蚀  膨胀
        erosion = cv2.erode(mask_, kernel_2, iterations=1)   
        dilation = cv2.dilate(erosion, kernel_4, iterations=1)  
        # 二值化，将滤波后的图像变成二值图像放在binary中
        ret, binary = cv2.threshold(dilation, 0, 255, cv2.THRESH_BINARY) 
        cnts = cv2.findContours(binary.copy(), cv2.RETR_EXTERNAL,
                                cv2.CHAIN_APPROX_SIMPLE)
        contours = imutils.grab_contours(cnts)
        ###----轮廓检测的第二种方法，二值化轮廓提取---start-####
        #### 进行高斯模糊操作
        # blurred = cv2.GaussianBlur(frame, (5, 5), 0)
        # # 进行图片灰度化
        # gray = cv2.cvtColor(blurred, cv2.COLOR_BGR2GRAY)
        # # 进行阈值分割
        # thresh = cv2.threshold(gray, 60, 255, cv2.THRESH_BINARY)[1]
        # # 在二值图片中寻找轮廓
        # contours = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        # contours = imutils.grab_contours(contours)
        ###----轮廓检测的第二种方法，二值化轮廓提取--end--####
        if contours is not None:
            for cnt in contours:  
                # 计算轮廓的边界框  
                x, y, w, h = cv2.boundingRect(cnt)
                contour_area = cv2.contourArea(cnt)
                if contour_area > min_area and contour_area < max_area:
                    cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 3)
                    approx = cv2.approxPolyDP(cnt, 0.016 * cv2.arcLength(cnt, True), True)
                    n_corners = len(approx)
                    # 三角形：三个顶点  
                    if n_corners == 3:
                        angle = self.triangle_angle(approx)
                        M = cv2.moments(cnt)
                        center_tri = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
                        cv2.drawContours(self.frame, [approx], -1, (0, 255, 0), 2)
                        self.position["triangle"] = [center_tri[0], center_tri[1], 0]
               
                    # 正方形：接近正方形的长宽比和四个直角  
                    elif n_corners == 4: 
                        angle = self.angel_count(cnt)
                        if abs(cv2.contourArea(cnt) / ((w*h) ** 0.5)) > 0.95:    
                            M = cv2.moments(cnt)
                            center_square = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
                            cv2.drawContours(self.frame, [approx], -1, (0, 255, 0), 2)
                            self.position["rectangle"] = [center_square[0], center_square[1], angle]

                    # 多边形：
                    elif n_corners >4 and n_corners < 8: 
                        angle = self.hexagon_angle(approx)
                        M = cv2.moments(cnt)
                        center_hexagon = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
                        cv2.drawContours(self.frame, [approx], -1, (0, 255, 0), 2)
                        self.position["sixangle"] = [center_hexagon[0], center_hexagon[1], 0]
    
                    # 圆形：近似为圆形的轮廓  
                    elif n_corners > 7 and n_corners < 100: 
                        angle = self.angel_count(cnt)  
                        M = cv2.moments(cnt)
                        center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
                        cv2.drawContours(self.frame, [approx], -1, (0, 255, 0), 2)
                        self.position["circle"] = [center[0], center[1], angle]
    
    def run(self,):
        #### 通过CV库函数获取视频流数据
        cap = cv2.VideoCapture(9,)
        cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))  

        while True:  
            ret, self.frame = cap.read()  
            if not ret:
                time.sleep(0.1)
                #### 图像一旦获取失败，不断循环获取图像
                cap = cv2.VideoCapture(9,)
                cap.set(cv2.CAP_PROP_FOURCC,cv2.VideoWriter_fourcc('M','J','P','G'))  
                print("Can't to capture from camera. Exiting ...")  
                break  
            
            #### 图像裁剪--感兴趣区域进行检测
            crop = np.zeros([1944,2592,3],np.uint8)
            crop[crop_x_min:crop_x_max,crop_y_min:crop_y_max] = self.frame[crop_x_min:crop_x_max,crop_y_min:crop_y_max]
            img = crop
            
            #### 二维码检测
            self.contour_recong(img)
            time.sleep(0.01)
            
            #### 图像显示与保存
            cv2.imshow('frame', self.frame)
            cv2.imwrite(f"crop.png",img)
            cv2.imwrite(f"frame.png",self.frame)
        
            # 按下'q'键退出循环  
            if cv2.waitKey(1) & 0xFF == ord('q'):  
                break  

        # 释放摄像头资源  
        cap.release()  
        # 关闭所有OpenCV窗口  
        cv2.destroyAllWindows()

a = frameClass()
a.run()